package com.ihr360.payroll.service.salarytasklet.step;

import com.ihr360.common.DateRange;
import com.ihr360.commons.model.type.EnrollAdjustFormula;
import com.ihr360.expr.ExprArray;
import com.ihr360.expr.ExprMissing;
import com.ihr360.expr.core.Expr;
import com.ihr360.expr.core.ExprVariable;
import com.ihr360.expr.data.ExprValueMeta;
import com.ihr360.expr.engine.VariableFetcher;
import com.ihr360.job.core.item.support.ListItemWriter;
import com.ihr360.job.core.item.support.MapMapItemWriter;
import com.ihr360.job.core.item.support.OneShotItemWriter;
import com.ihr360.payperiod.PayPeriodTerm;
import com.ihr360.payroll.model.dto.attendance.plan.AttendancePlan;
import com.ihr360.payroll.model.dto.reference.ReferenceService;
import com.ihr360.payroll.model.dto.salary.embeddable.RefServiceStatistics;
import com.ihr360.payroll.model.dto.salary.meta.SalaryField;
import com.ihr360.payroll.model.dto.salary.meta.system.SystemSalaryField;
import com.ihr360.payroll.model.dto.salary.plan.SalaryPlan;
import com.ihr360.payroll.service.salarytasklet.expr.engine.SalaryDependencyEngine;
import com.ihr360.sharedservice.model.WorkingCalendar;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
 * @author davidwei
 */
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class SalaryCalcContext {

    @Autowired
    public SystemCalcContext systemCalcContext;

    public boolean isMocking = false;

    public String companyId;
    /**
     * 薪资方案
     */
    public SalaryPlan salaryPlan;

    public PayPeriodTerm payPeriodTerm;

    /**
     * 福利设定
     */

    public boolean isReferenceBenefitData;
    /**
     * 考勤设定
     */

    /**
     * 病假是否启用分段计薪
     */
    public boolean sickLeavePhasedCalcEnable;
    /**
     * 事假是否启用分段计薪
     */
    public boolean personalLeavePhasedCalcEnable;

    /**
     * 分段调薪调整开始
     */

    public boolean salaryAdjustPhasedCalcEnable;
    /**
     * 核算的员工
     */
    public List<String> staffIdList;

    public Long salaryPlanId;

    /**
     * 合并计税基准方案
     */
    public Long basedOnSalaryPlanId;

    public Long payPeriodId;

    public Long attendancePlanId;

    public Long payrollConfigId;

    /**
     * 薪资表中是否包含社保福利项目
     */
    public boolean hasSIHFFields = false;

    /**
     * 薪资表中是否包含考勤项目
     */
    public boolean hasAttendanceFields = false;

    /**
     * 薪资周期范围
     */
    public DateRange payrollPeriodRange;

    /**
     * 考勤周期范围
     */
    public DateRange attendancePeriodRange;

    /**
     * 入离职调整标准计薪天数
     */

    public double monthlyEDStandardWorkingDays;

    public EnrollAdjustFormula enrollAdjustFormula;

    private RefServiceStatistics refServiceStatistics = new RefServiceStatistics();

    public OneShotItemWriter<Map<String, SalaryField>> salaryFieldsHolder = new OneShotItemWriter<>();

    public OneShotItemWriter<AttendancePlan> attendancePlanHolder = new OneShotItemWriter<>();

    /**
     * 工作日历
     */
    public OneShotItemWriter<WorkingCalendar> workingCalendarHolder = new OneShotItemWriter<>();

    /**
     * 税表的数据数据结构
     * {
     * 地区:{
     * 税表$纳税身份_纳税类型:[
     * 收入下限,收入上限,固定免税扣除额,免税扣除比例,应纳税所得额下限,应纳税所得额上限,税率,速算扣除数,
     * 收入下限,收入上限,固定免税扣除额,免税扣除比例,应纳税所得额下限,应纳税所得额上限,税率,速算扣除数,
     * ...
     * ]
     * }
     * }
     */
    public MapMapItemWriter<String, Map<String, ExprArray>> taxTableHolder = new MapMapItemWriter<>();

    public ListItemWriter<SystemSalaryField> systemSalaryFieldsHolder = new ListItemWriter<>();


    public OneShotItemWriter<List<ReferenceService>> refrenceServicesHolder = new OneShotItemWriter<>();


    public OneShotItemWriter<SalaryDependencyEngine> dependencyEngineHolder = new OneShotItemWriter<>();

    /**
     * 薪资方案中员工信息
     */
    public ListItemWriter<String> salaryPlanStaffListItemWriter = new ListItemWriter<>();


    public VariableFetcher variableFetcher = new VariableFetcher() {
        @Override
        public Expr variable(String variableId) {
            return null;
        }

        @Override
        public Expr notifyMissing(ExprVariable variable) {
            return ExprMissing.MISSING;
        }

        @Override
        public ExprValueMeta valueMeta(String variableId) {
            return null;
        }
    };


    public String getSystemSalaryFieldName(String fieldCode) {
        List<? extends SystemSalaryField> fields = systemSalaryFieldsHolder.getWrittenItems();
        if (systemCalcContext.mappedSystemFields == null) {
            systemCalcContext.mappedSystemFields = fields.stream().collect(Collectors.toMap(SystemSalaryField::getCode, f -> f));
        }
        SystemSalaryField field = systemCalcContext.mappedSystemFields.get(fieldCode);
        if (field != null) {
            return field.getName();
        }
        return null;
    }

    public SystemSalaryField getSystemSalaryField(String fieldCode) {
        List<? extends SystemSalaryField> fields = systemSalaryFieldsHolder.getWrittenItems();
        if (systemCalcContext.mappedSystemFields == null) {
            systemCalcContext.mappedSystemFields = fields.stream().collect(Collectors.toMap(SystemSalaryField::getCode, f -> f));
        }
        SystemSalaryField field = systemCalcContext.mappedSystemFields.get(fieldCode);
        return field;
    }

    public List<SystemSalaryField> getSalaryFieldsOfType(String typeCode) {
        List<? extends SystemSalaryField> fields = systemSalaryFieldsHolder.getWrittenItems();
        if (fields != null) {
            List<SystemSalaryField> salaryFields = fields.stream().filter(f -> f.getType() != null && typeCode.equals(f.getType().getCode())).collect(Collectors.toList());
            return salaryFields;
        }
        return Collections.emptyList();
    }

    /**
     * 薪资方案设定中是否关闭了分段计薪
     *
     * @return
     */
    public boolean isPhasedCalcDisabled() {
        return !sickLeavePhasedCalcEnable && !personalLeavePhasedCalcEnable;
    }

    public String getCompanyId() {
        return companyId;
    }

    public Long getTermId() {
        return payPeriodTerm.getId();
    }

    public Date getTermStartOn() {
        return payPeriodTerm.getStartOn();
    }

    public Date getTermEndOn() {
        return payPeriodTerm.getEndOn();
    }

    public int getPayPeriodYear() {
        return payPeriodTerm.getYear();
    }

    public int getPayPeriodMonth() {
        return payPeriodTerm.getMonth();
    }

    public RefServiceStatistics getRefServiceStatistics() {
        return refServiceStatistics;
    }

    public void setRefServiceStatistics(RefServiceStatistics refServiceStatistics) {
        this.refServiceStatistics = refServiceStatistics;
    }
}